(function(){
	var serviceRegistry = require('./ServiceRegistry'),
	    session         = require('Session').current,
	    chain           = require('CommandChain'),
	    StringUtils     = require('StringUtils'),
	    Collections     = require('Collections'),
	    cmdService      = require('CommandService'),
	    logFactory		= require('Log'),
	    ObjectUtils     = require('ObjectUtils');
	
	var format = StringUtils.format,
	    formatEach = StringUtils.formatEach,
        combine    = Collections.combine,
        toArray    = Collections.toArray,
        iterate    = Collections.iterate;
	
	var copy = ObjectUtils.copy;
	
	logFactory.addLogger({
		log : function(value){
			var dbg = window.document.getElementById('debugWindow'); 
			if( dbg ){
				dbg.innerHTML = value + '<br/>' + dbg.innerHTML;
			}
		},
		level : function(){
			return logFactory.Level.INFO;
		}
	});
	
	var scroller = window.document.getElementById('scroller-tab');
	var tabBodies = [];
	iterate( window.document.getElementsByTagName('div'), function(tabBody){
		if( tabBody.getAttribute('class') === 'tab-body' ){
			tabBodies.push( tabBody );
		}
	});
	var tabContainer = window.document.getElementById('tab-container');
	var tabHeader = window.document.getElementById('tab-header');
	var tabs = function(){ 
		var tags = [];
		iterate( tabHeader.getElementsByTagName('a'), function(tab){
			var clz = tab.getAttribute('class');
			if(clz && clz.match(/.*tab.*/))
				tags.push( tab );
		}); 
		return tags;
	};
	
	var selectTabDelegate = function(tab, index){
		return function(){
			iterate(tabBodies, function(tabBody, i){
				if( i == index)
					tabBody.style['z-index'] = 1000;
				else
					tabBody.style['z-index'] = 0;
			});
		};
	}
	
	iterate(tabs(), function(tab, index){
		tab.onclick = selectTabDelegate(tab, index);
	});
	console.log(tabs());
	
	var userService;
	var roomService;
	var db = {};
	
	var onServicesLoaded = function(){
		console.log('Services Loaded');
		session.aliasService = new org.jsmud.AliasService(db.alias);
		session.itemService  = new org.jsmud.ItemService(db.item);
		userService = new org.jsmud.UserService(db.user);
		roomService = new org.jsmud.RoomService(db.room);
		
		userService.findByExample({username:'player'}, function(user){
			if(user && user.length == 1){
				user = user[0];
				session.setUser(user);
				var loadRandomRoom = function(){
					roomService.list(function(rooms){
						session.setRoom(rooms[0]);
						cmdService.execute('describe',updateConsole);
					})
				};
				if( user.getRoomId() ){
					roomService.findById(user.getRoomId(), function(room){
						if( room ){
							session.setRoom(room);
							cmdService.execute('describe',updateConsole);
						}else{
							loadRandomRoom();
						}
					})
				}else{
					loadRandomRoom();
				}
			}else{
				console.log('User not found');
				console.log(user);
				user = {username:'player'};
				userService.save(user);
			}
		});
	};
	
	serviceRegistry.get('mongo', function(mongo){
		db.room = mongo.getDb('room');
		db.user = mongo.getDb('user');
		db.alias = mongo.getDb('alias');
		db.item  = mongo.getDb('item');
	
		var setup = chain.create();
		var proceed = function(){
			setup.proceed();
		}
		setup
			.add({method:db.alias.on, arguments:['ready', proceed], scope:db.alias})
			.add({method:db.item.on , arguments:['ready', proceed], scope:db.item})
			.add({method:db.room.on , arguments:['ready', proceed], scope:db.room})
			.add({method:db.user.on , arguments:['ready', proceed], scope:db.user})
			.add({method:onServicesLoaded, arguments:[]})
			.execute();
	});
	
	spanWrap = function(collection){
		return combine(formatEach(collection, '${0}&nbsp;'))
	}
	
	var updateConsole = function(msg){
		if( cmdWindow.lastChild){
			cmdWindow.removeChild(cmdWindow.lastChild);
		}
		var html = msg;
		if( msg.toHTML ){
			console.log("toHTML")
			html = msg.toHTML();
		}
		if( typeof html === 'string' ){
			cmdWindow.innerHTML += format('<div>${html}</div><div>><div>', {html:html});
			scroller.scrollTop = scroller.scrollHeight;
		}else{
			var tab = document.createElement('span');
			tab.innerHTML = format('<a href="javascript:void(0)" class="tab"><span>${name}</span></a>', {name:'Editor'});
			tab.childNodes[0].onclick = selectTabDelegate(tab, tabs().length);
			tabHeader.appendChild(tab);
			
			var tabBody = document.createElement('div');
			tabBody.setAttribute('class', 'tab-body');
			var textarea = document.createElement('textarea');
			textarea.setAttribute('class', 'fill');
			textarea.value = StringUtils.toEditable(msg.data).replace(/\t/g, '   ');

			var savebtn = document.createElement('input')
			savebtn.value = 'Save';
			savebtn.type  = 'button';
			savebtn.style.width = '50px';
			savebtn.onclick = function(){
				var result = eval( '(' + textarea.value + ')' );
				var onDone = function(){
					if( msg.save ) msg.save();
				};
				copy(result)
					.withFactory({
						canCreate : function(obj){
							return typeof obj === 'function'
						},
						create : function(obj, callback){
							callback('' + obj);
						}
					})
					.withCallback(onDone)
					.into( msg.data );
			};
			
			tabBody.appendChild(textarea);
			tabBody.appendChild(savebtn);
			
			tabContainer.appendChild(tabBody);
		}
	}
	var execute = function(){
		var value = cmd.value;
		updateConsole('>'+value);
		cmd.value = '';
		if( value.match(/clear/) ){
			cmdWindow.innerHTML = '';
		}
		else if( value ){
			cmdService.execute(value, updateConsole);
		}
		clearHighlight();
	}
	var clearHighlight = function(){
		var elements = cmdWindow.getElementsByTagName('span');
		for(var index=0; index < elements.length; index++){
			var element = elements[index];
			element.s1 = null;
			if( element.style ) element.style.border = null;
		}		
	}
	
	var highlight = function(incr){
		var elements = cmdWindow.getElementsByTagName('span');
		var found = false;
		var selected = null;
		for(var index=0; index < elements.length; index++){
			var element = elements[index];
			if( !element.s1 ) continue;

			found = true;
			element.s1 = null;
			if( element.style ) element.style.border = null;

			element = elements[index+incr];
			selected = element;
			break;
		}
		if( elements.length && !found ){
			selected = elements[elements.length-1];
		}
		if( selected ){
			selected.s1 = 'true';
			selected.style.border = '1px solid #F00';
			var txt = cmd.value;
			updateTextSelection(cmd, selected.innerText);
		}
	}
	var updateTextSelection = function(input, value){
		var txt = input.value;
		if( input.selectionStart ){
			var start = input.selectionStart;
			var end = input.selectionEnd;
			if( (txt[start-1] == "'" && txt[start] == "'") ||
				(txt[start-1] == '"' && txt[start] == '"')){
				input.value = txt.substring(0, start);
				input.value += value;
				input.value += txt.substring(start);
				input.selectionStart = start;
				input.selectionEnd = start + value.length;
			}
			else if(start != end){
				input.value = txt.substring(0, start);
				input.value += value;
				input.value += txt.substring(end);
				input.selectionStart = start;
				input.selectionEnd = start + value.length;
			}
			else{
				var cmdArray = toArray(txt, ' ');
				cmdArray[ cmdArray.length - 1 ] = value;
				input.value = Collections.combine(cmdArray, ' ');
				input.selectionStart = start + value.length;
				input.selectionEnd = start + value.length;
			}
		}else{
			input.value = value
			input.selectionStart = start;
			input.selectionEnd = start + value.length;
		}
	};
	
	var autoCompleteData = function(results){
		if(results.err ){
			updateConsole(results.err);
		}else{
			updateTextSelection(cmd, results.base);
			if( results.values.length > 1 ){
				updateConsole('>');
				displayOptions(results, results.base);
			}
		}
	}
	
	var displayOptions = function(options, commonBase){
		updateConsole('>');
		var html = options.toHTML ? options.toHTML() : spanWrap(options.values);
		if( html ){
			updateTextSelection(cmd, commonBase);
			updateConsole(html);
		}
	}
	
	var doAutoComplete = function(response){
		var value = response.values[0];
		var commandOnPrompt = cmd.value.match('^' + value);
		if( !commandOnPrompt || cmd.value.indexOf(' ') < 0 ){
			cmd.value = value + ' ';
		}else{
			cmdService.get(value, function(command){
				var txt = toArray(cmd.value)[1];
				command.autoComplete(txt, autoCompleteData);
			});
		}
	}
	
	var autoComplete = function(response){
		var failed = response.err;
		var isMatch = !failed && response.values.length == 1;
		
		if( failed ){
			updateConsole(response.err);
		}else if( isMatch ){
			doAutoComplete(response);
		}else{
			displayOptions(response, response.base);
		}
	}
	
	promptBtn.onclick = function(e){ execute() };
	cmd.onkeypress = function(e){ 
		if(e.keyCode ==13){ 
			execute();
		}
	};
	cmd.onkeydown = function(e){
		var TAB = 9;
		var LEFT = 37;
		var UP  = 38;
		var RIGHT = 39;
		var DOWN = 40;
		if( e.keyCode == TAB ){
			if( e.preventDefault ) e.preventDefault();
			
			cmdService.execute('listCommands ' + cmd.value, autoComplete);
			return false;
		}else if( (e.keyCode == UP || e.keyCode == LEFT) && e.ctrlKey ){
			if( e.preventDefault ) e.preventDefault();
			highlight(-1);
			return false;
		}else if( (e.keyCode == DOWN || e.keyCode == RIGHT) && e.ctrlKey ){
			if( e.preventDefault ) e.preventDefault();
			highlight(1);
			return false;
		}
	}
	cmd.focus();
})()